package com.example.graphmovieapp.repository;

import com.example.graphmovieapp.domain.entity.Person;
import com.example.graphmovieapp.domain.entity.Movie;
import com.example.graphmovieapp.dto.MovieDTO;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.query.Param;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

/**
 * PersonRepository接口，提供对Person实体的数据访问操作
 * 
 * @author GraphMovieApp
 * @version 1.0
 */
@Repository
public interface PersonRepository extends Neo4jRepository<Person, Long> {

    /**
     * 按姓名查找人物
     * 
     * @param name 人物姓名
     * @return 匹配的人物，如果不存在则返回Optional.empty()
     */
    Optional<Person> findByName(String name);

    /**
     * 按出生年份查找人物
     * 
     * @param born 出生年份
     * @return 匹配的人物列表
     */
    List<Person> findByBorn(Integer born);

    /**
     * 按姓名模糊查询人物
     * 
     * @param name 姓名关键字
     * @return 包含关键字的人物列表
     */
    List<Person> findByNameContaining(String name);

    /**
     * 按姓名模糊查询人物（支持分页）
     * 
     * @param name 姓名关键字
     * @param pageable 分页参数
     * @return 分页的人物列表
     */
    Page<Person> findByNameContaining(String name, Pageable pageable);

    /**
     * 查找指定演员参演的所有电影
     *
     * @param name 演员姓名
     * @return 该演员参演的电影列表
     */
    @Query("MATCH (p:Person {name: $name})-[:ACTED_IN]->(m:Movie) RETURN m")
    List<Movie> findMoviesActedByPerson(@Param("name") String name);

    /**
     * 查找指定演员参演的所有电影（支持分页）
     *
     * @param name 演员姓名
     * @param pageable 分页参数
     * @return 分页的电影列表
     */
    @Query(value = "MATCH (p:Person {name: $name})-[:ACTED_IN]->(m:Movie) RETURN m ORDER BY m.title SKIP $skip LIMIT $limit",
           countQuery = "MATCH (p:Person {name: $name})-[:ACTED_IN]->(m:Movie) RETURN count(m)")
    Page<Movie> findMoviesActedByPerson(@Param("name") String name, Pageable pageable);

    /**
     * 查找指定导演执导的所有电影
     *
     * @param name 导演姓名
     * @return 该导演执导的电影列表
     */
    @Query("MATCH (p:Person {name: $name})-[:DIRECTED]->(m:Movie) RETURN m")
    List<Movie> findMoviesDirectedByPerson(@Param("name") String name);

    /**
     * 查找指定导演执导的所有电影（支持分页）
     *
     * @param name 导演姓名
     * @param pageable 分页参数
     * @return 分页的电影列表
     */
    @Query(value = "MATCH (p:Person {name: $name})-[:DIRECTED]->(m:Movie) RETURN m ORDER BY m.title SKIP $skip LIMIT $limit",
           countQuery = "MATCH (p:Person {name: $name})-[:DIRECTED]->(m:Movie) RETURN count(m)")
    Page<Movie> findMoviesDirectedByPerson(@Param("name") String name, Pageable pageable);

    /**
     * 查找参演指定电影的演员
     * 
     * @param title 电影标题
     * @return 参演该电影的演员列表
     */
    @Query("MATCH (p:Person)-[:ACTED_IN]->(m:Movie {title: $title}) RETURN p")
    List<Person> findActorsInMovie(@Param("title") String title);

    /**
     * 查找参演指定电影的演员（支持分页）
     *
     * @param title 电影标题
     * @param pageable 分页参数
     * @return 分页的演员列表
     */
    @Query(value = "MATCH (p:Person)-[:ACTED_IN]->(m:Movie {title: $title}) RETURN p ORDER BY p.name SKIP $skip LIMIT $limit",
           countQuery = "MATCH (p:Person)-[:ACTED_IN]->(m:Movie {title: $title}) RETURN count(p)")
    Page<Person> findActorsInMovie(@Param("title") String title, Pageable pageable);

    /**
     * 查找指定电影的导演
     * 
     * @param title 电影标题
     * @return 该电影的导演列表
     */
    @Query("MATCH (p:Person)-[:DIRECTED]->(m:Movie {title: $title}) RETURN p")
    List<Person> findDirectorsOfMovie(@Param("title") String title);

    /**
     * 查找指定电影的导演（支持分页）
     *
     * @param title 电影标题
     * @param pageable 分页参数
     * @return 分页的导演列表
     */
    @Query(value = "MATCH (p:Person)-[:DIRECTED]->(m:Movie {title: $title}) RETURN p ORDER BY p.name SKIP $skip LIMIT $limit",
           countQuery = "MATCH (p:Person)-[:DIRECTED]->(m:Movie {title: $title}) RETURN count(p)")
    Page<Person> findDirectorsOfMovie(@Param("title") String title, Pageable pageable);
}